package cn.turboinfo.fuyang.api.domain.mini.usecase.shop;

import cn.turboinfo.fuyang.api.domain.common.handler.shop.ShopDataFactory;
import cn.turboinfo.fuyang.api.domain.common.service.shop.HousekeepingShopService;
import cn.turboinfo.fuyang.api.domain.common.usecase.AbstractUseCase;
import cn.turboinfo.fuyang.api.entity.common.constant.AreaConstants;
import cn.turboinfo.fuyang.api.entity.common.enumeration.shop.ShopFilterType;
import cn.turboinfo.fuyang.api.entity.common.enumeration.shop.ShopSortType;
import cn.turboinfo.fuyang.api.entity.common.enumeration.shop.ShopStatus;
import cn.turboinfo.fuyang.api.entity.common.fo.shop.ViewShopFO;
import cn.turboinfo.fuyang.api.entity.common.pojo.shop.HousekeepingShop;
import cn.turboinfo.fuyang.api.entity.mini.fo.shop.MiniNearbyShop;
import kotlin.Pair;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import net.sunshow.toolkit.core.qbean.helper.component.mapper.BeanMapper;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 搜索附近门店
 *
 * @author sunshow
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class MiniSearchNearbyShopUseCase extends AbstractUseCase<MiniSearchNearbyShopUseCase.InputData, MiniSearchNearbyShopUseCase.OutputData> {

    private final HousekeepingShopService housekeepingShopService;

    private final ShopDataFactory shopDataFactory;

    @Override
    protected OutputData doAction(InputData inputData) {
        BigDecimal longitude = inputData.getLongitude();
        BigDecimal latitude = inputData.getLatitude();
        Long areaCode = inputData.getAreaCode();
        Long categoryId = inputData.getCategoryId();
        ShopFilterType filterType = Objects.requireNonNullElse(inputData.getFilterType(), ShopFilterType.DEFAULT);
        ShopSortType sortType = Objects.requireNonNullElse(inputData.getSortType(), ShopSortType.DEFAULT);

        List<HousekeepingShop> shopList = new ArrayList<>();

        // 距离
        Map<Long, BigDecimal> shopIdDistanceMap;

        if (longitude != null && latitude != null) {
            // 获取距离50公里内最近的所有门店
            List<Pair<HousekeepingShop, BigDecimal>> pairList = housekeepingShopService.findByGeoRadius(longitude, latitude, 50D, null);
            shopList = pairList.stream()
                    .map(Pair::getFirst)
                    .collect(Collectors.toList());
            shopIdDistanceMap = pairList.stream()
                    .collect(
                            Collectors.toMap(
                                    pair -> pair.getFirst().getId(),
                                    Pair::getSecond
                            )
                    );
        } else {
            shopList = housekeepingShopService.findByCityCode(AreaConstants.DEFAULT_CITY_ID);
            shopIdDistanceMap = new HashMap<>();
        }

        // 如何门店列表是空 则不按地区去查询
        if (shopList.isEmpty()) {
            shopList = housekeepingShopService.findByCityCode(AreaConstants.DEFAULT_CITY_ID);
        }

        // 门店ID集合
        Set<Long> shopIdSet = shopList.stream()
                .map(HousekeepingShop::getId)
                .collect(Collectors.toSet());

        Map<Long, Set<Long>> shopIdCategoryIdMap = housekeepingShopService.batchFindShopCategory(shopIdSet);

        LocalDateTime now = LocalDateTime.now();

        // 过滤掉无效数据
        shopList.stream()
                .filter(shop -> {
                    if (shop.getStatus() == ShopStatus.REVIEWED) {
                        // 过滤掉不在指定区域的门店
                        if (areaCode != null && !shop.getAreaCode().equals(areaCode)) {
                            return false;
                        }
                        // 过滤掉不在指定分类的门店
                        if (categoryId != null) {
                            // 没有服务分类的过滤掉
                            if (!shopIdCategoryIdMap.containsKey(shop.getId())) {
                                return false;
                            }
                            // 不包含筛选分类的过滤掉
                            return shopIdCategoryIdMap.get(shop.getId()).contains(categoryId);
                        }
                        return true;
                    }

                    return false;
                })
                .filter(shop -> {
                    switch (filterType) {
                        case RECENTLY -> {
                            // 如果是最近入驻, 只保留最近90天入驻的门店
                            Duration duration = Duration.between(shop.getFoundDate().atStartOfDay(), now);
                            return (!duration.isNegative()) && duration.toDays() <= 90 && shop.getCreditScore().doubleValue() > 90;
                        }
                        case EARLY_BRANDED -> {
                            // 如果是品牌老店, 只保留最近180天之前入驻的门店
                            Duration duration = Duration.between(shop.getFoundDate().atStartOfDay(), now);
                            return (!duration.isNegative()) && duration.toDays() > 180 && shop.getCreditScore().doubleValue() > 90;
                        }
                        default -> {
                            return true;
                        }
                    }
                }).collect(Collectors.toList());

        // 拼装企业信息
        shopDataFactory.assembleCompany(shopList);
        // 拼装附件信息
        shopDataFactory.assembleAttachment(shopList);

        // 逐个应用过滤条件
        List<MiniNearbyShop> nearbyShopList = shopList.stream()
                .map(shop -> {
                    MiniNearbyShop nearbyShop = new MiniNearbyShop();
                    shopDataFactory.maskInfo(shop);
                    ViewShopFO shopFO = BeanMapper.map(shop, ViewShopFO.class);

                    nearbyShop.setShop(shopFO);
                    nearbyShop.setDistance(shopIdDistanceMap.get(shop.getId()));
                    return nearbyShop;
                })
                .toList();

        return OutputData.builder()
                .nearbyShopList(nearbyShopList)
                .build();
    }

    @EqualsAndHashCode(callSuper = true)
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    public static class InputData extends AbstractUseCase.InputData {

        /**
         * 经度
         */
        private BigDecimal longitude;

        /**
         * 纬度
         */
        private BigDecimal latitude;

        /**
         * 区编码
         */
        private Long areaCode;

        /**
         * 二级服务ID
         */
        private Long categoryId;


        /**
         * 排序方式
         */
        private ShopSortType sortType;

        /**
         * 筛选方式
         */
        private ShopFilterType filterType;
    }

    @Getter
    @Setter
    @Builder
    public static class OutputData extends AbstractUseCase.OutputData {

        /**
         * 附近门店列表
         */
        private List<MiniNearbyShop> nearbyShopList;

    }
}
